<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!-- 关闭下移动端手机缩放功能 -->
    <meta name="viewport"
        content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
    <title>Document</title>
    <style>
        /* 通配符，设置所有元素不要包含默认内外边距 */
        * {
            margin: 0;
            padding: 0;
        }   

        #app {
            position: relative;
            /* vw CSS新单位 设备宽度 100 百分之百的设备屏幕宽度 */
            width: 100vw;
            /* vh CSS新单位 设备宽度 100 百分之百的设备屏幕高度 */
            height: 100vh;
            /* 如果子元素超出父元素的范围，我们就让其隐藏 */
            overflow: hidden;
            background-image: url(./images/bg.png);
            background-size: cover;
        }

        .my-plane {
            /* 让飞机动起来要让飞机也设置绝对定位 */
            position: absolute;
            width: 66px;
            height: 80px;
            background-image: url(./images/plane.gif);
            z-index: 10;
        }

        .cover {
            position: absolute;
            left: 0px;
            top: 0px;
            width: 100%;
            height: 100%;
            z-index: 999;
            /* background-color: rgba(255, 0, 0, 0.1); */
        }

        .bullet {
            position: absolute;
            width: 24px;
            height: 14px;
            background-image: url(./images/bullet.png);
        }

        .enemy1 {
            position: absolute;
            width: 34px;
            height: 24px;
            background-image: url(./images/enemy1.png);
        }

        .enemy2 {
            position: absolute;
            width: 46px;
            height: 60px;
            background-image: url(./images/enemy2.png);
        }

        .enemy3 {
            position: absolute;
            width: 110px;
            height: 164px;
            background-image: url(./images/enemy3.png);
        }

        .bomb {
            position: absolute;
            width: 36px;
            height: 36px;
            background-image: url(./images/bomb.svg);
            
        }

        .damage-ball {
            position: absolute;
            width: 22px;
            height: 22px;
            border-radius: 50%;

        }
    </style>
    <!-- 引入外部js文件，用于实现碰撞检测 -->
    <script src="./tool.js"></script>
</head>

<body>
    <div id="app">
        <div class="score">分数：0</div>
        <div class="my-plane"></div>
        <!-- 他就是一个透明得到屏幕挡住页面所有的飞机和子弹，防止鼠标误触， 未来通过js在 cover 上绑定鼠标的移动事件，让飞机追着手指跑 -->
        <div class="cover"></div>
    </div>


    <script>
        // js 实现飞机大战的主逻辑

        // 1. 获取cover元素（触摸屏），
        // DOM编程 使用 js 操作页面中的元素
        // 从文档中查询css选择器是 .cover 的元素
        var cover = document.querySelector('.cover')

        // 获取 cover 宽高, DOM 编程的官方 API
        var screenW = cover.offsetWidth
        var screenH = cover.offsetHeight

        console.log(screenH);
        console.log(screenW);


        // 1.1获取自己的飞机
        // 驼峰命名法
        var myPlane = document.querySelector(".my-plane")
        // 给飞机增加攻击力属性
        myPlane.damage = 1

        console.log(myPlane);

        // 提前创建 offsetX offsetY用来存储飞机的偏移量
        // 提前创建让变量成为全局变量，任何地方都可以访问它
        var offsetX = screenW / 2 - 33
        var offsetY = screenH - 80

        // 初始化飞机的位置
        myPlane.style.left = offsetX + 'px'
        myPlane.style.top = offsetY + 'px'

        // 2. 给cover元素绑定手指按压移动事件
        // 事件绑定的函数会自动接受一个参数 event 事件对象 
        // 是一个用来描述当前手指touchmove事件对象 
        cover.ontouchmove = function (event) {
            // console.log(event);
            // console.log('x:', event.touches[0].clientX);
            // console.log('y:', event.touches[0].clientY);
            // 将手指移动的像素转化成整数
            let x = parseInt(event.touches[0].clientX)
            let y = parseInt(event.touches[0].clientY)
            // console.log('x', x);
            // console.log('y', y);
            // 3. 将手指移动的偏移量设置到飞机的定位样式中
            // 3.1 注意 如果直接将鼠标偏移量设置给飞机会导致飞机左上角跟着手指移动 
            // myPlane.style.left = x + 'px'
            // myPlane.style.top = y + 'px'
            // 3.2 解决方案通过数学运算计算飞机偏移量真正的值：
            //      距离左边：鼠标的X偏移量 - 飞机宽度的一半
            //      距离左边：鼠标的Y偏移量 - 飞机高度的一半
            offsetX = x - 33
            offsetY = y - 40

            // 边界处理，不能让飞机超出容器

            // 左边不能越界 offsetX 不能小于最小值 0 
            if (offsetX < 0) {
                offsetX = 0
            }

            // 右边不能越界 offsetX 不能大于最大值 屏幕宽度 - 飞机自己的宽度 
            // 屏幕宽度 其实就是 cover 的宽度
            if (offsetX > screenW - 66) {
                offsetX = screenW - 66
            }

            // 上边不能越界 offsetY 不能小于最小值 0
            if (offsetY < 0) {
                offsetY = 0
            }
            // 下边不能越界 offsetY 不能大于最大值 屏幕高度 - 飞机自己的高度 
            if (offsetY > screenH - 80) {
                offsetY = screenH - 80
            }

            myPlane.style.left = offsetX + 'px'
            myPlane.style.top = offsetY + 'px'


            // myPlane.style.left = x - 33 + 'px'
            // myPlane.style.top = y - 40 + 'px'
        }

        // 游戏区域的容器元素
        var app = document.querySelector('#app')

        // 变量记录本次得分行为是否是爆炸得分
        var booming = false

        // 创建计时器标记（计时器的身份证），用于结束游戏（停止计时器）
        var createBulletTimer = null // 生成子弹
        var moveTimer = null // 移动的计时器
        var createEnemy1Timer = null // 生成小飞机的计时器
        var createEnemy2Timer = null // 生成中飞机的计时器
        var createEnemy3Timer = null // 生成大飞机的计时器
        var createDamageBall = null // 生成增加伤害到小球

        // 创建计时器
        createBulletTimer = setInterval(function () {
            // 每600毫秒生成一颗子弹
            var bullet = document.createElement('div')
            // 给子弹设置class 与 css匹配展示对应的UI
            bullet.className = 'bullet'
            // 将子弹添加到页面游戏区域
            app.appendChild(bullet)
            // 设置子弹的出生点跟随飞机
            // 水平方向子弹的left值 等于飞机左上角 offsetX + 飞机宽度的一半 - 子弹宽度的一半
            bullet.style.left = offsetX + 33 - 12 + 'px'
            bullet.style.top = offsetY + 'px'
            bullet.boom = function() {

            }

        }, 300)

        // 移动计时器
        // 子弹飞行， 再开启一个计时器,计时器的时间为30毫秒执行一次保证子弹动画在30帧（动画比较流畅）
        moveTimer = setInterval(function () {
            // 获取所有的子弹 querySelector 只能获取满足条件的第一个元素， querySelectorAll 获取所有满足条件的元素
            var bulletArr = document.querySelectorAll('.bullet')
            // console.log(bulletArr);
            // 遍历子弹
            for (var i = 0; i < bulletArr.length; i++) {
                // 获取每一个子弹
                var b = bulletArr[i]

                

                // 子弹向上飞 获取 当前子弹的位置，然后通过减法运算更新子弹的 style的top属性   
                // console.log('子弹当前位置', b.offsetTop);

                b.style.top = b.offsetTop - 6 + 'px'

                // console.log(b);

                // 子弹飞出屏幕的处理 子弹高度是14，完全飞出屏幕需要-14
                if (b.offsetTop < -14) {
                    app.removeChild(b)
                }

                // 碰撞检测实现， for拿到了每一颗子弹，让每颗子弹与所有的敌机一个一个的尝试是否碰撞
                // 获取所有敌机不论敌机1 ， 敌机2 ， 敌机3 
                var allEnemyArr = document.querySelectorAll('.enemy1,.enemy2,.enemy3')

                // 遍历所有敌机
                for (var j = 0; j < allEnemyArr.length; j++) {
                    var e = allEnemyArr[j]

                    // 爆炸的敌机不会再挨打， 即子弹不会与该敌机进行碰撞检查
                    if(e.hp <= 0) {
                        continue
                    }

                    if (impact(b, e)) {
                        //打爆敌机清除敌机
                        // app.removeChild(e1)
                        // 我们自己的飞机有攻击力，子弹打到敌机时扣除敌机自身攻击力的血量
                        e.hp = e.hp - myPlane.damage
                        // 当敌机生命值为 0 时 回收飞机 
                        if (e.hp <= 0) {
                            //  调用boom方法回收敌机
                            e.boom()
                        }
                        // console.log(e1.hp);
                        app.removeChild(b)
                        break; // 子弹与敌机发生碰撞 跳出循环 不进行后续判断 提高应用性能
                    }
                }



            }

            // 获取所有敌机
            var allEnemyArr = document.querySelectorAll('.enemy1,.enemy2,.enemy3')
            // 敌机的移动
            for (var i = 0; i < allEnemyArr.length; i++) {

                var e = allEnemyArr[i]
                // 血量为0表示该飞机已经是爆炸的飞机了，不需要向下飞
                if(e.hp <= 0) {
                    continue // 不执行下一次代码直接进入下一个循环
                }

                e.style.top = e.offsetTop + e.speed + 'px'

                if (impact(e, myPlane)) {
                    gameOver()
                    return // 结束整个函数 不再执行后续代码
                }

                // 清除越界敌机
                if (e.offsetTop > screenH + e.offsetHeight) {
                    app.removeChild(e)
                }

            }

            // 炸弹移动
            var bomb = document.querySelector('.bomb')
            // 页面中有炸弹才移动
            if (bomb) {
                bomb.style.top = bomb.offsetTop + 12 + 'px'

                if (bomb.offsetTop > screenH + 36) {
                    app.removeChild(bomb)
                }

                if (impact(bomb, myPlane)) { // 自己的飞机捡到炸弹
                    // 爆炸获得的分数不会奖励新的炸弹
                    booming = true

                    // 延迟执行
                    setTimeout(function () {
                        booming = false
                    }, 300)

                    app.removeChild(bomb)
                    // 让页面种所有敌机都要爆炸
                    var allEnemy = document.querySelectorAll('.enemy1,.enemy2,.enemy3')

                    for (var i = 0; i < allEnemy.length; i++) {
                        var e = allEnemy[i]
                        if(e.hp <= 0) { // 已经死亡的敌机不需要再次爆炸
                            continue
                        }
                        e.hp = 0  //强制让敌机血量为0
                        e.boom() // 调用自身的爆炸方法
                    }
                }
            }

            var allDamageBalls = document.querySelectorAll('.damage-ball')
            for (var i = 0; i < allDamageBalls.length; i++) {
                var b = allDamageBalls[i]
                b.style.top = b.offsetTop + 5 +'px' 
                // 每次移动时都更新下自身的颜色
                b.style.backgroundColor = getRandomColor()
                
                if(b.offsetTop >= screenH + 22) {
                    app.removeChild(b)  
                }

                // 小球与飞机进行碰撞检测加攻击力
                if(impact(b, myPlane)) {
                    app.removeChild(b)
                    myPlane.damage = myPlane.damage + 1
                }

            }
        }, 30)

        // 计时器创建小敌机
        createEnemy1Timer = setInterval(function () {
            var enemy1 = document.createElement('div')
            enemy1.className = 'enemy1'
            app.appendChild(enemy1)
            // 设置敌机随机位置 范围x轴范围  0 ~ 屏幕宽度-34
            var randomX = parseInt(Math.random() * (screenW - 34 + 1))
            enemy1.style.left = randomX + 'px'
            // 添加生命值
            enemy1.hp = 1
            // 添加敌机速度
            enemy1.speed = 6
            // 添加分数
            enemy1.score = 1
            // 敌机爆炸gif图
            enemy1.boomGif  = 'url(./images/enemy1b.gif)'
            enemy1.boomTime = 1000
            // 飞机爆炸
            enemy1.boom = boom
        }, 700)

        // 计时器创建中敌机
        createEnemy2Timer = setInterval(function () {
            var enemy2 = document.createElement('div')
            enemy2.className = 'enemy2'
            app.appendChild(enemy2)
            // 设置敌机随机位置 范围x轴范围  0 ~ 屏幕宽度-34
            var randomX = parseInt(Math.random() * (screenW - 46 + 1))
            enemy2.style.top = -60 + 'px'
            enemy2.style.left = randomX + 'px'
            // 添加生命值
            enemy2.hp = 4
            // 添加敌机速度
            enemy2.speed = 4
            // 添加分数
            enemy2.score = 4
            // 敌机爆炸的gif
            enemy2.boomGif = 'url(./images/enemy2b.gif)'

            enemy2.boomTime = 2000
            // 飞机爆炸
            enemy2.boom = boom
        }, 1500)

        // 计时器创建大敌机
        createEnemy3Timer = setInterval(function () {
            var enemy3 = document.createElement('div')
            enemy3.className = 'enemy3'
            app.appendChild(enemy3)

            // 设置敌机随机位置 范围x轴范围  0 ~ 屏幕宽度-34
            var randomX = parseInt(Math.random() * (screenW - 110 + 1))
            enemy3.style.left = randomX + 'px'
            enemy3.style.top = -164 + 'px'
            // 添加生命值
            enemy3.hp = 10
            // 添加敌机速度
            enemy3.speed = 2
            // 添加分数
            enemy3.score = 15

            enemy3.boomGif = 'url(./images/enemy3b.gif)'

            enemy3.boomTime = 3000

            // 飞机爆炸
            enemy3.boom = boom
        }, 4000)

        // 创建力量果实
        createDamageBall = setInterval(function () {
            var ball = document.createElement('div')
            ball.className = 'damage-ball'
            ball.style.left = parseInt(Math.random() * (screenW - 22)) + 'px'
            ball.style.backgroundColor = getRandomColor()
            app.appendChild(ball)
        }, 5000)

        // 定义全局分数
        var score = 0
        // 获取展示分数的lable元素    
        var scoreLabel = document.querySelector('.score')

        function boom() {
            // this 调用该函数得到对象，其实就是那个需要爆炸飞机
            // this 谁调用该方法this就是谁
            // 飞机爆炸的效果
            // 计时器延迟时间用来显示飞机爆炸gif图的时间
            
            this.style.backgroundImage = this.boomGif
           
            // this 可能是大飞机 中飞机 小飞机

            var self = this
            // 使用self保证延迟执行内部可以获取到指向敌机的 this
            setTimeout(function(){
                app.removeChild(self)
            }, this.boomTime)
            
            // console.log(this.score);

            score = score + this.score
            // 设置对称型标签内部的文本内容
            scoreLabel.innerHTML = '分数：' + score

            // 分数每次发生更新后，都需要判断是否满足创建炸弹的条件     
            createBomb()
        }

        // 创建炸弹函数
        // 我们需要顶一个一个 record 记录用于存储上一次释放炸弹时 （成绩 / 100）取整后的值， 
        // 当成绩发生改变时 （新的成绩 / 100）取整 大于 record 表示用户成绩又突破了100 分可以，再次奖励一个炸弹
        var record = 0 // 初始化record
        function createBomb() {
            // 玩家每获得100分游戏页面就会创建一个炸弹
            var s = parseInt(score / 20)

            if (s > record) { // 奖励炸弹
                // 更新 record
                record = s

                // 判断页面中同一时间有且仅有一个炸弹 
                var oldBomb = document.querySelector('.bomb')
                // console.log(old);
                // 页面没有炸弹才会创建一个新的炸弹
                if (!oldBomb && !booming) {
                    var bomb = document.createElement('div')
                    bomb.className = 'bomb'
                    bomb.style.left = parseInt(Math.random() * (screenW - 36 + 1)) + 'px'
                    app.appendChild(bomb)
                }

            }

        }

        // 游戏结束的方法,关闭所有计时器
        function gameOver() {
            // 关闭计时器的方法,  clearInterval(计时器的id)
            clearInterval(createBulletTimer)
            clearInterval(moveTimer)
            clearInterval(createEnemy1Timer)
            clearInterval(createEnemy2Timer)
            clearInterval(createEnemy3Timer)
            clearInterval(createDamageBall)
            // 取消敌机的移动，取消鼠标移动事件
            cover.ontouchmove = null

            myPlane.style.backgroundImage = 'url(./images/planeb.gif)'
        }

        // 封装函数用于生成随机颜色
        function getRandomColor() {
            var red = parseInt(Math.random() * 256)
            var green = parseInt(Math.random() * 256)
            var blue = parseInt(Math.random() * 256)
            return "rgb(" + red + "," + green + "," + blue + ")"
        }
    </script>
</body>

</html>